#ifndef __TYLE_H__
#define __TYLE_H__

#include <stdio.h>
#include <stdarg.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifdef NO_DLL
#  define DLLFUNC
#else
#ifdef TYLE_BUILD_SHARED
#  define DLLFUNC	__declspec(dllexport)
#else
#  define DLLFUNC	__declspec(dllimport)
#endif
#endif

enum Tyle_Object_Type
{
	TOT_Null,
	TOT_List,
	TOT_Int,
	TOT_Float,
	TOT_String,
	TOT_Expr,
	TOT_Ref,
	TOT_Map,
	TOT_RegExp
};

typedef void *Tyle_Object;

/* ------- Session functions ------- */

void                 DLLFUNC Tyle_init          ();
void                 DLLFUNC Tyle_quit          ();
Tyle_Object          DLLFUNC Tyle_evaluate      ( const char *program ); 

void                 DLLFUNC Tyle_free          ( Tyle_Object o ); // use Tyle_free on all objects
void                 DLLFUNC Tyle_stackString   ( const char *str, int len=-1 );
void                 DLLFUNC Tyle_block         (); // use blocking when stacking a string before evaluating in multithread use.
void                 DLLFUNC Tyle_unblock       ();

/* ------- Object functions ------- */

Tyle_Object_Type     DLLFUNC Tyle_getType  ( Tyle_Object o ); 
int                  DLLFUNC Tyle_length   ( Tyle_Object o );
Tyle_Object          DLLFUNC Tyle_index    ( Tyle_Object o, int index );
Tyle_Object          DLLFUNC Tyle_indexMap ( Tyle_Object o, Tyle_Object index );

int                  DLLFUNC Tyle_toInt    (Tyle_Object o); 
float                DLLFUNC Tyle_toFloat  (Tyle_Object o); 
char *               DLLFUNC Tyle_toString (Tyle_Object o, /*OUT*/ Tyle_Object *anchor, int *outLength=0); // free anchor after use of string
char *               DLLFUNC Tyle_toTyle   (Tyle_Object o, /*OUT*/ Tyle_Object *anchor, int *outLength=0); // free anchor after use of string

#ifdef __cplusplus
}

/* ------- C++ Wrapper API ------- */
namespace Tyle
{

class Object;
	
class Object
{	
	friend class TextOutput;
	friend class TyleOutput;
	Tyle_Object m_o;
public:
	Object(Tyle_Object o):m_o(o) {}
	Object(const char *program) { m_o = Tyle_evaluate(program); } 
	Object(int bufsize, const char *format,...)
	{	char *program = new char[bufsize];
		va_list va;
		va_start(va, format);
		vsprintf(program, format, va);
		va_end(va);
		m_o = Tyle_evaluate(program);
		delete[] program;
	} 
	~Object() { Tyle_free(m_o); }
	int getLength() { return Tyle_length(m_o); }
	int toInt() const { return Tyle_toInt(m_o); }
	float toFloat() const { return Tyle_toFloat(m_o); }
	Tyle_Object_Type getType() { return Tyle_getType(m_o); }
	Object operator[](int i) const { return Object(Tyle_index(m_o,i)); }
	Object operator[](const Object &i) const { return Object(Tyle_indexMap(m_o,i.m_o)); }
};

class String /* private class */
{
protected:
	Tyle_Object m_anchor;
	char *m_s;
	int len;
	String() {}
public:
	int length() { return len; }
	~String() { Tyle_free(m_anchor); }
	operator char *() const { return m_s; }
};

class TextOutput: public String
{
public:
	TextOutput(const Object &o) {  m_s=Tyle_toString(o.m_o,&m_anchor,&len); }
};

class TyleOutput: public String
{
public:
	TyleOutput(const Object &o) {  m_s=Tyle_toTyle(o.m_o,&m_anchor,&len); }
};

} // namespace
#endif //#ifdef __cplusplus

#endif
